using Microsoft.Extensions.Options;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Threading.Tasks;

namespace Infrastructure.Redis
{
    /// <summary>
    /// Redis操作帮助类
    /// </summary>
    public class RedisHelper : IRedisHelper, IDisposable
    {
        private readonly ConnectionMultiplexer _redis;
        private readonly IDatabase _db;
        private readonly RedisOptions _options;
        private bool _disposed;

        /// <summary>
        /// 初始化Redis帮助类
        /// </summary>
        /// <param name="options">Redis配置选项</param>
        public RedisHelper(IOptions<RedisOptions> options)
        {
            // 从依赖注入获取Redis配置选项
            _options = options.Value;
            
            // 创建Redis连接配置对象
            var configOptions = new ConfigurationOptions
            {
                // 设置Redis服务器连接地址(IP:端口)
                EndPoints = { _options.GetConnectionString() },
                
                // 设置默认使用的数据库索引
                DefaultDatabase = _options.DefaultDatabase,
                
                // 设置连接超时时间(毫秒)
                ConnectTimeout = _options.ConnectTimeout,
                
                // 设置同步操作超时时间(毫秒)
                SyncTimeout = _options.SyncTimeout,
                
                // 连接失败时不立即中止，允许重试
                AbortOnConnectFail = false,
                
                // 允许执行管理命令(如FLUSHDB等)
                AllowAdmin = true,
                
                // 设置Redis服务器访问密码
                Password = _options.Password,
                
                // 是否使用SSL加密连接
                Ssl = _options.UseSsl,
                
                // 连接失败时的重试次数
                ConnectRetry = _options.RetryCount,
                
                // 使用线性重试策略，指定重试间隔时间(毫秒)
                ReconnectRetryPolicy = new LinearRetry(_options.RetryDelay)
            };
            
            // 使用配置创建Redis连接多路复用器，管理与Redis服务器的连接池
            _redis = ConnectionMultiplexer.Connect(configOptions);
            
            // 获取Redis数据库实例，用于后续执行Redis操作
            _db = _redis.GetDatabase();
        }

        #region 字符串操作

        /// <inheritdoc />
        public async Task<T?> GetAsync<T>(string key)
        {
            key = AddPrefix(key);
            var value = await _db.StringGetAsync(key);
            return value.HasValue ? Deserialize<T>(value) : default;
        }

        /// <inheritdoc />
        public T? Get<T>(string key)
        {
            key = AddPrefix(key);
            var value = _db.StringGet(key);
            return value.HasValue ? Deserialize<T>(value) : default;
        }

        /// <inheritdoc />
        public async Task<string?> GetStringAsync(string key)
        {
            key = AddPrefix(key);
            var value = await _db.StringGetAsync(key);
            return value.HasValue ? value.ToString() : null;
        }

        /// <inheritdoc />
        public string? GetString(string key)
        {
            key = AddPrefix(key);
            var value = _db.StringGet(key);
            return value.HasValue ? value.ToString() : null;
        }

        /// <inheritdoc />
        public async Task<bool> SetAsync<T>(string key, T value, TimeSpan? expiry = null)
        {
            key = AddPrefix(key);
            var serializedValue = Serialize(value);
            return await _db.StringSetAsync(key, serializedValue, expiry);
        }

        /// <inheritdoc />
        public bool Set<T>(string key, T value, TimeSpan? expiry = null)
        {
            key = AddPrefix(key);
            var serializedValue = Serialize(value);
            return _db.StringSet(key, serializedValue, expiry);
        }

        /// <inheritdoc />
        public async Task<bool> SetStringAsync(string key, string value, TimeSpan? expiry = null)
        {
            key = AddPrefix(key);
            return await _db.StringSetAsync(key, value, expiry);
        }

        /// <inheritdoc />
        public bool SetString(string key, string value, TimeSpan? expiry = null)
        {
            key = AddPrefix(key);
            return _db.StringSet(key, value, expiry);
        }

        #endregion

        #region 键操作

        /// <inheritdoc />
        public async Task<bool> RemoveAsync(string key)
        {
            key = AddPrefix(key);
            return await _db.KeyDeleteAsync(key);
        }

        /// <inheritdoc />
        public bool Remove(string key)
        {
            key = AddPrefix(key);
            return _db.KeyDelete(key);
        }

        /// <inheritdoc />
        public async Task<bool> ExistsAsync(string key)
        {
            key = AddPrefix(key);
            return await _db.KeyExistsAsync(key);
        }

        /// <inheritdoc />
        public bool Exists(string key)
        {
            key = AddPrefix(key);
            return _db.KeyExists(key);
        }

        /// <inheritdoc />
        public async Task<bool> SetExpiryAsync(string key, TimeSpan expiry)
        {
            key = AddPrefix(key);
            return await _db.KeyExpireAsync(key, expiry);
        }

        /// <inheritdoc />
        public bool SetExpiry(string key, TimeSpan expiry)
        {
            key = AddPrefix(key);
            return _db.KeyExpire(key, expiry);
        }

        #endregion

        #region 哈希表操作

        /// <inheritdoc />
        public async Task<T?> HashGetAsync<T>(string key, string field)
        {
            key = AddPrefix(key);
            var value = await _db.HashGetAsync(key, field);
            return value.HasValue ? Deserialize<T>(value) : default;
        }

        /// <inheritdoc />
        public T? HashGet<T>(string key, string field)
        {
            key = AddPrefix(key);
            var value = _db.HashGet(key, field);
            return value.HasValue ? Deserialize<T>(value) : default;
        }

        /// <inheritdoc />
        public async Task<bool> HashSetAsync<T>(string key, string field, T value)
        {
            key = AddPrefix(key);
            var serializedValue = Serialize(value);
            return await _db.HashSetAsync(key, field, serializedValue);
        }

        /// <inheritdoc />
        public bool HashSet<T>(string key, string field, T value)
        {
            key = AddPrefix(key);
            var serializedValue = Serialize(value);
            return _db.HashSet(key, field, serializedValue);
        }

        /// <inheritdoc />
        public async Task<bool> HashDeleteAsync(string key, string field)
        {
            key = AddPrefix(key);
            return await _db.HashDeleteAsync(key, field);
        }

        /// <inheritdoc />
        public bool HashDelete(string key, string field)
        {
            key = AddPrefix(key);
            return _db.HashDelete(key, field);
        }

        /// <inheritdoc />
        public async Task<bool> HashExistsAsync(string key, string field)
        {
            key = AddPrefix(key);
            return await _db.HashExistsAsync(key, field);
        }

        /// <inheritdoc />
        public bool HashExists(string key, string field)
        {
            key = AddPrefix(key);
            return _db.HashExists(key, field);
        }

        /// <inheritdoc />
        public async Task<Dictionary<string, T>> HashGetAllAsync<T>(string key)
        {
            key = AddPrefix(key);
            var entries = await _db.HashGetAllAsync(key);
            var result = new Dictionary<string, T>();
            
            foreach (var entry in entries)
            {
                if (entry.Value.HasValue)
                {
                    result.Add(entry.Name.ToString(), Deserialize<T>(entry.Value));
                }
            }
            
            return result;
        }

        /// <inheritdoc />
        public Dictionary<string, T> HashGetAll<T>(string key)
        {
            key = AddPrefix(key);
            var entries = _db.HashGetAll(key);
            var result = new Dictionary<string, T>();
            
            foreach (var entry in entries)
            {
                if (entry.Value.HasValue)
                {
                    result.Add(entry.Name.ToString(), Deserialize<T>(entry.Value));
                }
            }
            
            return result;
        }

        #endregion

        #region 辅助方法

        /// <summary>
        /// 添加前缀
        /// </summary>
        /// <param name="key">键</param>
        /// <returns>带前缀的键</returns>
        private string AddPrefix(string key)
        {
            return string.IsNullOrEmpty(_options.KeyPrefix) ? key : $"{_options.KeyPrefix}:{key}";
        }

        /// <summary>
        /// 序列化对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="value">对象值</param>
        /// <returns>序列化后的字符串</returns>
        private string Serialize<T>(T value)
        {
            return JsonSerializer.Serialize(value, new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            });
        }

        /// <summary>
        /// 反序列化对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="value">序列化字符串</param>
        /// <returns>反序列化后的对象</returns>
        private T Deserialize<T>(string value)
        {
            return JsonSerializer.Deserialize<T>(value, new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            })!;
        }

        #endregion

        #region IDisposable接口实现

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        /// <param name="disposing">是否正在释放</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _redis?.Dispose();
                }

                _disposed = true;
            }
        }

        #endregion
    }
} 